package com.deepface.web.controller.faceLab;

import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.deepface.common.config.DflConfig;
import com.deepface.common.core.controller.BaseController;
import com.deepface.common.core.domain.AjaxResult;
import com.deepface.common.core.page.TableDataInfo;
import com.deepface.common.utils.DateUtils;
import com.deepface.common.utils.SecurityUtils;
import com.deepface.common.utils.StringUtils;
import com.deepface.common.utils.file.FileTypeUtils;
import com.deepface.common.utils.file.FileUploadUtils;
import com.deepface.common.utils.spring.SpringUtils;
import com.deepface.framework.web.domain.server.Sys;
import com.deepface.system.domain.SysFaceJob;
import com.deepface.system.domain.SysFaceJobGroup;
import com.deepface.system.domain.po.DflJobGroupPo;
import com.deepface.system.service.SysFaceJobGroupService;
import com.deepface.system.service.SysFaceJobService;
import com.deepface.system.service.SysFileInfoService;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;

import java.util.HashMap;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import javax.annotation.Resource;
import org.apache.commons.lang3.StringEscapeUtils;
import org.aspectj.weaver.loadtime.Aj;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.InputStreamResource;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.HttpClientErrorException;
import org.springframework.web.client.HttpServerErrorException;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.multipart.MultipartFile;

/**
 * @ClassName SysFaceJobGroupController
 * @Description
 * @Author 74707
 * @Date 2023/12/20 11:44
 * @Version V1.0
 */
@CrossOrigin
@RestController
@EnableAsync
@RequestMapping("/system/dfl")
public class SysFaceJobGroupController extends BaseController {

  @Resource
  private SysFaceJobGroupService sysFaceJobGroupService;

  @Resource
  private SysFaceJobService sysFaceJobService;

  @Autowired
  private SysFileInfoService sysFileInfoService;


  @GetMapping(value = "/listJobGroup")
  public TableDataInfo listJobGroup() {
    startPage();
    Long id = SecurityUtils.getUserId();
    List<SysFaceJobGroup> list =
        sysFaceJobGroupService.list(Wrappers.<SysFaceJobGroup>lambdaQuery()
            .eq(SysFaceJobGroup::getUserId, id).eq(SysFaceJobGroup::getDelFlag, 0));
    return getDataTable(list);
  }

  @GetMapping(value = "/listJobGroupByPlus")
  public TableDataInfo listJobGroup(DflJobGroupPo dto) {
    startPage();
    Long id = SecurityUtils.getUserId();
    List<SysFaceJobGroup> list =
        sysFaceJobGroupService.list(Wrappers.<SysFaceJobGroup>lambdaQuery()
            .eq(SysFaceJobGroup::getUserId, id).eq(SysFaceJobGroup::getDelFlag, 0)
            .like(Objects.nonNull(dto.getJobGroupName()), SysFaceJobGroup::getJobGroupName,
                dto.getJobGroupName()));
    return getDataTable(list);
  }

  @PostMapping(value = "/createJobGroup")
  public AjaxResult createJobGroup(@RequestParam("name") String jobGroupName) {
    SysFaceJobGroup sysFaceJobGroup = new SysFaceJobGroup();
    sysFaceJobGroup.setJobGroupName(jobGroupName);
    sysFaceJobGroupService.insertSysFaceJobGroup(sysFaceJobGroup);
    System.out.println(sysFaceJobGroup.getJobGroupId());
    HashMap<String, Object> data = new HashMap<>();
    data.put("faceJobGroupId", sysFaceJobGroup.getJobGroupId());
    data.put("faceJobGroupName", sysFaceJobGroup.getJobGroupName());
    return AjaxResult.success(data);
  }

  @PostMapping(value = "/alterJobGroup")
  public AjaxResult alterJobGroup(@RequestParam("id") Long id,
      @RequestParam("name") String jobGroupName) {
    SysFaceJobGroup sysFaceJobGroup = new SysFaceJobGroup();
    sysFaceJobGroup.setJobGroupName(jobGroupName);
    sysFaceJobGroup.setUpdateBy(SecurityUtils.getUsername());
    sysFaceJobGroup.setUpdateTime(DateUtils.getNowDate());
    Boolean res = sysFaceJobGroupService.update(sysFaceJobGroup,
        Wrappers.<SysFaceJobGroup>lambdaUpdate()
            .eq(SysFaceJobGroup::getDelFlag, "0")
            .eq(SysFaceJobGroup::getJobGroupId, id));
    if (res) {
      return AjaxResult.success("更新成功");
    } else {
      return AjaxResult.error("更新失败");
    }
  }

  @PostMapping(value = "/deleteJobGroup/{jobid}")
  public AjaxResult deleteJobGroup(@PathVariable("jobid") Long id) {
    SysFaceJobGroup sysFaceJobGroup = new SysFaceJobGroup();
    sysFaceJobGroup.setDelFlag("1");
    Boolean res = sysFaceJobGroupService.update(sysFaceJobGroup,
        Wrappers.<SysFaceJobGroup>lambdaUpdate()
            .eq(SysFaceJobGroup::getDelFlag, "0").eq(SysFaceJobGroup::getJobGroupId, id));
    SysFaceJob sysFaceJob = new SysFaceJob();
    //联动删除
    sysFaceJob.setDelFlag("1");
    sysFaceJobService.update(sysFaceJob, Wrappers.<SysFaceJob>lambdaUpdate()
        .eq(SysFaceJob::getDelFlag, "0").eq(SysFaceJob::getJobGroupId, id));

    if (res) {
      return AjaxResult.success("删除成功");
    } else {
      return AjaxResult.error("删除失败");
    }
  }

  @PostMapping("/uploadFileForGroup")
  public AjaxResult uploadFile(@RequestParam("file") MultipartFile file,
      @RequestParam Long jobGroupId,
      @RequestParam String fileNowName,
      @RequestParam int totalChunks) {
    if (file == null) {
      return AjaxResult.warn("请选择文件进行上传");
    }

    String jobInputDir = DflConfig.getRootFilePath() +
        SecurityUtils.getUserId().toString() + "/" + jobGroupId + "/";

    System.out.println("total:");
    System.out.println(totalChunks);

    SysFaceJobGroupController ss = SpringUtils.getBean(SysFaceJobGroupController.class);

    int chunkSize = 2 * 1024 * 1024; // Assuming 2MB is the chunk size
    if (file.getSize() <= chunkSize) {
      // Handle the case where the file is smaller than one chunk
      CompletableFuture<String> future = ss.uploadChunkAsync(file, jobInputDir, fileNowName, 1, 1);
      future.join();
      return AjaxResult.success("文件上传完成，无需分片");
    }
    List<CompletableFuture<String>> futures = IntStream.rangeClosed(1, totalChunks)
        .mapToObj(chunkNumber -> ss.uploadChunkAsync(file, jobInputDir, fileNowName, chunkNumber,
            totalChunks))
        .collect(Collectors.toList());

    CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();

    return AjaxResult.success("分片完成");
  }


  @Async
  public CompletableFuture<String> uploadChunkAsync(MultipartFile file, String jobInputDir,
      String fileNowName, int chunkNumber, int totalChunks) {

    try {
      // 分片大小，例如每片1MB
      int chunkSize = 2 * 1024 * 1024;
      long offset = (chunkNumber - 1) * chunkSize;
      long partSize = Math.min(chunkSize, file.getSize() - offset);

      byte[] buffer = new byte[(int) partSize];
      try (InputStream inputStream = file.getInputStream()) {
        inputStream.skip(offset);
        inputStream.read(buffer);
      }

      // 创建分片资源
      ByteArrayResource resource = new ByteArrayResource(buffer){
        @Override
        public String getFilename() {
          return fileNowName + "_part_" + chunkNumber;
        }
      };

      if (resource == null) {
        System.out.println("Resource is null");
      } else {
        System.out.println("Resource is not null");
      }

      System.out.println("chunkNumber:");
      System.out.println(chunkNumber);
      String suffix = FileTypeUtils.getFileType(file.getOriginalFilename());
      String chunkFileName = jobInputDir + fileNowName + "." + suffix + ".part_" + chunkNumber;

      HttpHeaders headers = new HttpHeaders();
      headers.setContentType(MediaType.MULTIPART_FORM_DATA);
      MultiValueMap<String, Object> body = new LinkedMultiValueMap<>();
      body.add("file", resource);
      body.add("filePath", chunkFileName);
      body.add("chunkNumber", chunkNumber);
      body.add("totalChunks", totalChunks);
      System.out.println(chunkFileName);
      System.out.println(resource);

      HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity<>(body, headers);
      System.out.println("Printing requestEntity:");
      System.out.println(requestEntity);
      RestTemplate restTemplate = new RestTemplate();
      ResponseEntity<String> response = restTemplate.postForEntity(
          "http://123.57.18.66:5022/upload",
          requestEntity, String.class);
      System.out.println("post");

      return CompletableFuture.completedFuture(response.getBody());
    } catch (Exception e) {
      e.printStackTrace();
      return CompletableFuture.completedFuture("Error uploading chunk: " + chunkNumber);
    }
  }

  @PostMapping("/uploadFileForGroup-raw")
  public AjaxResult uploadFile2(@RequestParam("file") MultipartFile[] files,
      @RequestParam Long jobGroupId, @RequestParam String fileNowName) {
    if (files == null || files.length == 0) {
      return AjaxResult.error("请至少选择一个文件进行上传");
    }

    String jobInputDir = DflConfig.getRootFilePath() +
        SecurityUtils.getUserId().toString() + "/" + jobGroupId + "/";
    if (StringUtils.isNotBlank(jobInputDir) == false) {
      return AjaxResult.error("文件目标上传路径为空，请重新创建任务");
    }

    for (MultipartFile file : files) {
      try {
        String suffix = FileTypeUtils.getFileType(file.getOriginalFilename());
        System.out.println("----------正在上传啊啊啊啊---------");
        String uploadResponse = FileUploadUtils.uploadByHttp("http://123.57.18.66:5022/upload",
            file, jobInputDir + fileNowName + "." + suffix);
        if (!uploadResponse.startsWith("文件上传成功")) {
          // 如果上传不成功，立即返回错误信息
          return AjaxResult.error("文件上传失败: " + uploadResponse);
        }
        //sysFileInfo插入
        sysFileInfoService.insertSysFileInfo(file, jobInputDir, fileNowName);
      } catch (Exception e) {
        return AjaxResult.error("文件上传有误" + e.getMessage());
      }
    }
    return AjaxResult.success("成功上传文件");
  }

  @GetMapping("/downloadFileForGroup")
  public ResponseEntity<InputStreamResource> downloadFile(@RequestParam("id") Long jobGroupId) {
    // 构造内网文件的相对路径
    String jobInputDir = DflConfig.getRootFilePath() +
        SecurityUtils.getUserId().toString() + "/" + jobGroupId + "/";
    String filename = "result.mp4"; // 假设文件名是已知的
    String filePath = jobInputDir + filename;

    // 假设Flask应用的下载路由模式
    String targetUrl = "http://123.57.18.66:5022/download";

    // 调用FileUploadUtils.downloadByHttp()下载文件
    InputStreamResource fileStream = FileUploadUtils.downloadByHttp(targetUrl, filePath);

    if (fileStream == null) {
      // 如果无法下载文件（例如文件不存在），返回404状态码
      return ResponseEntity.notFound().build();
    }

    HttpHeaders headers = new HttpHeaders();
    String newFileName = "result.mp4";
    headers.add(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + newFileName + "\"");
    headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);

    // 返回文件流
    return ResponseEntity.ok()
        .headers(headers)
        .body(fileStream);
  }

}